package cn.gjculture.shopping.api.service.impl;

import cn.gjculture.shopping.api.dao.*;
import cn.gjculture.shopping.api.entity.*;
import cn.gjculture.shopping.api.service.*;
import cn.gjculture.shopping.api.util.DateUtil;
import cn.gjculture.shopping.api.util.UUIDUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class PayServiceImpl implements PayService {

    @Autowired
    PayDao payDao;
    @Autowired
    CommonUpdateMapper commonUpdateMapper;
    @Autowired
    OrderDao orderDao;
    @Autowired
    InterfaceService interfaceService;
    @Autowired
    MerchantService merchantService;
    @Autowired
    PayMapper payMapper;

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    IdService idService;

    @Autowired
    TokenService tokenService;


    @Override
    public int insert(Pay pay) {
        pay.setPayId(UUIDUtil.getUUID());
        pay.setInsertTime(DateUtil.getTimestamp());
        pay.setPayType(Pay.ThirdType.QYF.getValue());
        return payDao.insert(pay);
    }


    @Override
    public boolean refund(Order o) {
        Pay pay = payDao.queryByOrderId(o.getOrderId());
        Pay refund = new Pay();
        refund.setPayId(UUIDUtil.getUUID());
        refund.setOrderId(pay.getOrderId());
        refund.setAmount(pay.getAmount());
        refund.setCustomerId(o.getCustomerId());
        refund.setThirdType(Pay.ThirdType.QYF.getValue());
        refund.setPayType(Pay.PayType.REFUND.getValue());
        refund.setInsertTime(DateUtil.getTimestamp());
        refund.setInAndOut(Pay.InAndOut.OUT.getValue());
        refund.setThirdSwiftNumber(pay.getThirdSwiftNumber());
        refund.setRefundId(pay.getPayId());
        refund.setSwiftNumber(pay.getSwiftNumber());
        refund.setIsRefund(0);

        payDao.insert(refund);
        interfaceService.refund(refund);
        return true;
    }

    @Override
    public int payBack(String code, String msg, JSONObject responseParam) {
        if ("88".equals(code)) {
            String orderId = responseParam.getString("merMerOrderNo");
            String thirdSwiftNumber = responseParam.getString("orderNo");
            Order order = new Order();
            order.setOrderId(orderId);
            order.setStatus(8);
            order.setUpdateTime(DateUtil.getTimestamp());
            orderDao.updateStatus(order);
            Pay pay = new Pay();
            pay.setOrderId(orderId);
            pay.setThirdSwiftNumber(thirdSwiftNumber);
            pay.setSuccess(8);
            pay.setPayTime(DateUtil.getTimestamp());
            commonUpdateMapper.updatePayByOrderId(pay);
            log.info(msg);
        } else {
            //TODO
            log.info(msg);
        }
        return 1;
    }

    @Override
    public String unifyPay(UnifyParam unifyParam) {
        Pay pay = new Pay(true);
        pay.setPayType(Pay.PayType.IMMEDIATELY_PAY.getValue());
        pay.setInsertTime(DateUtil.getTimestamp());
        pay.setInAndOut(Pay.InAndOut.IN.getValue());
        pay.setOrderId(unifyParam.getOrderId());
        pay.setThirdType(Pay.ThirdType.QYF.getValue());
        pay.setAmount(unifyParam.getPayAmount());
        payDao.insert(pay);
        return interfaceService.unifyPay(unifyParam);
    }

    @Override
    public String transfer(List<SupplierSubAccount> subAccounts) {
        log.info("转账开始");
        Pay pay = new Pay();
        pay.setSonMerNo(subAccounts.get(0).getSonMerNo());
        pay.setPayId(UUIDUtil.getUUID());
        pay.setInsertTime(DateUtil.getTimestamp());
        String amount = this.sumAmount(subAccounts);
        pay.setAmount(amount);
        pay.setInsertTime(DateUtil.getTimestamp());
        pay.setInAndOut(Pay.InAndOut.OUT.getValue());
        pay.setPayType(Pay.PayType.SUPPLIER_WITHDRAW.getValue());
        pay.setThirdType(Pay.ThirdType.QYF.getValue());
        Merchant merchant = merchantService.queryByBelongId(subAccounts.get(0).getSupplierId());
        boolean ret = interfaceService.transfer(pay, merchant);
        if (ret) {
            pay.setPayTime(DateUtil.getTimestamp());
            pay.setSuccess(8);
            payDao.insert(pay);
            for (SupplierSubAccount s : subAccounts) {
                s.setStatus(0);
                payDao.updateStatusSupplierSubAccount(s, pay.getPayId(), DateUtil.getTimestamp());
            }
        }

        return null;
    }

    private String sumAmount(List<SupplierSubAccount> s) {
        BigDecimal sum = new BigDecimal("0");
        for (SupplierSubAccount subAccount : s) {
            sum = sum.add(new BigDecimal(subAccount.getAmount()));
        }
        return sum.setScale(2, BigDecimal.ROUND_DOWN).toString();
    }

    @Override
    public void quartzSupplierTransfer() {
        log.info("定时分账开始");
        Map<String, List<SupplierSubAccount>> subAccountMap = mergeSubAccount();
        for (Map.Entry<String, List<SupplierSubAccount>> s : subAccountMap.entrySet()) {
            transfer(s.getValue());
        }
    }

    @Override
    public List<Pay> queryByCustomer(Customer customerNo) {
        return payMapper.queryByCustomer(customerNo);
    }

    @Override
    public List<Map> querySubAccountByCustomerNo(String customerNo, String consumerNo, Integer come) {
        Long currentTime=System.currentTimeMillis();
        Map<String,Object> params=new HashMap<>();
        params.put("customerNo",customerNo);
        params.put("consumerNo",consumerNo);
        params.put("currentTime",currentTime);
        params.put("come",come);
        return payMapper.querySubAccountByCustomerNo(params);
    }

    @Override
    public Map queryWithdraw(Long customerNo) {
       return  payMapper.queryWithdraw(customerNo);
    }

    @Override
    public int updateSubAccountByOrderId(SubAccount sub) {
        return  payDao.updateSubAccountByOrderId(sub);
    }

    @Override
    public int updateSupplierSubAccount(SupplierSubAccount supplierSubAccount) {
        return payDao.updateSupplierSubAccount();
    }

    @Override
    public int refundBack(String code, String msg, JSONObject responseParam) {
        if ("88".equals(code)) {
            //TODO 退款回调
//            String swiftNumber = responseParam.getString("merMerOrderNo");
//            String thirdSwiftNumber = responseParam.getString("orderNo");
//            Pay pay = payDao.queryById(payId);
//            Order order = new Order();
//            order.setOrderId(pay.getOrderId());
//            order.setRefundStatus(8);
//            order.setStatus(null);
//            order.setUpdateTime(DateUtil.getTimestamp());
//            orderMapper.update(order);
//            pay.setPayId(payId);
//            pay.setThirdSwiftNumber(thirdSwiftNumber);
//            pay.setSuccess(8);
//            pay.setPayTime(DateUtil.getTimestamp());
//            commonUpdateMapper.updatePayById(pay);
//            RefundFlow refundFlow = new RefundFlow();
//            refundFlow.setOrderId(order.getOrderId());
//            refundFlow.setStatus(8);
//            refundFlow.setRefundSuccessTime(DateUtil.getTimestamp());
//            orderMapper.updateRefundFlowByOrderId(refundFlow);
            log.info(msg);
        } else {
            log.info(msg);
        }
        return 1;
    }

    @Override
    public int withdraw(String token, JSONObject data, Return ret) {
        String merchantId = data.getString("merchantId");
        String withdrawAmount = data.getString("withdrawAmount");
        Merchant merchant = merchantService.queryById(merchantId);
        if (merchant != null && !StringUtils.isEmpty(merchant.getSonMerNo())) {
            boolean result=this.transferWithdraw(token, merchant, withdrawAmount);
            if(result){
                return 1;
            }
        }
        return 0;
    }

    @Override
    public int withdraw(String token, String withdrawAmount, String merchantId, Return ret) {
        Merchant merchant = merchantService.queryById(merchantId);
        if (merchant != null && !StringUtils.isEmpty(merchant.getSonMerNo())) {
            boolean result=this.transferWithdraw(token,merchant, withdrawAmount);
            if(result){
                return 1;
            }
        }
        return 0;
    }

    @Override
    public List<Map> queryWithdrawSystem() {
        return  payMapper.queryWithdrawSystem();
    }

    private boolean transferWithdraw(String tokenId, Merchant merchant, String withdrawAmount) {
        Pay pay = new Pay();
        pay.setSonMerNo(merchant.getSonMerNo());
        pay.setPayId(UUIDUtil.getUUID());
        pay.setInsertTime(DateUtil.getTimestamp());
        pay.setAmount(withdrawAmount);
        Token token=tokenService.queryByToken(tokenId);
        if(token==null||StringUtils.isEmpty(token.getCustomerId())) return false;
        pay.setCustomerId(token.getCustomerId());
        pay.setInsertTime(DateUtil.getTimestamp());
        pay.setInAndOut(Pay.InAndOut.OUT.getValue());
        pay.setThirdType(Pay.ThirdType.QYF.getValue());
        pay.setSwiftNumber(idService.queryOrderNo());
        pay.setPayType(Pay.PayType.ADMIN_WITHDRAW.getValue());
        boolean ret = interfaceService.transfer(pay, merchant);
        if (ret) {
            pay.setPayTime(DateUtil.getTimestamp());
            pay.setSuccess(8);
            payDao.insert(pay);
            return true;
        }
        return false;
    }

    private Map<String, List<SupplierSubAccount>> mergeSubAccount() {
        List<SupplierSubAccount> subAccounts = payDao.querySupplierSubAccount(2);
        Map<String, List<SupplierSubAccount>> subAccountMap = new HashMap<>();
        for (SupplierSubAccount subAccount : subAccounts) {
            if (subAccount != null && !StringUtils.isEmpty(subAccount.getSonMerNo()) && subAccount.getDeadline() > 0
                    && subAccount.getDeadline() <= System.currentTimeMillis()) {
                if (subAccountMap.containsKey(subAccount.getSonMerNo())) {
                    List<SupplierSubAccount> sub = subAccountMap.get(subAccount.getSonMerNo());
                    sub.add(subAccount);
//                    sub.setAmount(new BigDecimal(sub.getAmount()).add(new BigDecimal(subAccount.getAmount())).toString());
                } else {
                    List<SupplierSubAccount> sub = new ArrayList<>();
                    sub.add(subAccount);
                    subAccountMap.put(subAccount.getSonMerNo(), sub);
                }
            }
        }
        return subAccountMap;
    }

    @Override
    public List<SubAccount> querySubAccount(String customerId) {
        return payDao.querySubAccount(customerId);
    }
}
